﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
// std headers

// qt headers
#include <QListWidget>
#include <QScrollBar>
#include <QCheckBox>
#include <QPushButton>
#include <QStackedLayout>
#include <QLabel>

// gcmp headers

// custom headers
#include "StandardParametersChoosingDialog.h"
#include "IParameter.gcs.h"
#include "IParameterDefinition.h"
#include "CustomReply.h"
#include "PropertyService.h"
#include "ICategoryProperty.h"
#include "GbmpNew.h"
#include "DebugMessage.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

namespace gmepgcs
{
    StandardParametersChoosingDialog::StandardParametersChoosingDialog(QWidget *parent, Qt::WindowFlags flags) :
        MessageDialog(parent, flags),
        m_categoryProperty(nullptr),
        m_mpExistedParameterDefinitions(),
        m_initialSelectedParameterDefinitions(),
        m_finalSelectedParameterDefinitions(),
        m_errorMessage(),
        m_lwParamters(nullptr)
    {
        Init();
    }

    StandardParametersChoosingDialog::~StandardParametersChoosingDialog()
    {

    }

    StandardParametersChoosingDialog *StandardParametersChoosingDialog::s_pInstance = nullptr;
    StandardParametersChoosingDialog * StandardParametersChoosingDialog::Get(QWidget * parent)
    {
        if (!StandardParametersChoosingDialog::s_pInstance)
        {
            StandardParametersChoosingDialog::s_pInstance = NEW_AS_QT(StandardParametersChoosingDialog,parent);
            StandardParametersChoosingDialog::s_pInstance->setObjectName("StandardParametersChoosingDialog");
        }
        else if (StandardParametersChoosingDialog::s_pInstance->parentWidget() != parent)
        {
            StandardParametersChoosingDialog::s_pInstance->deleteLater();
            StandardParametersChoosingDialog::s_pInstance = NEW_AS_QT(StandardParametersChoosingDialog,parent);
            StandardParametersChoosingDialog::s_pInstance->setObjectName("StandardParametersChoosingDialog");
        }
        return StandardParametersChoosingDialog::s_pInstance;
    }

    MessageDialog::MessageDialogResult StandardParametersChoosingDialog::Show(
        std::shared_ptr<ICategoryProperty> & categoryProperty, 
        const std::map<std::wstring, std::shared_ptr<IParameterDefinition>>& existedParameterDefinitions,
        std::map<std::wstring, std::shared_ptr<IParameterDefinition>> &finalAdded,
        std::map<std::wstring, std::shared_ptr<IParameterDefinition>> &finalRemoved,
        QWidget * parent)
    {
        StandardParametersChoosingDialog *pDialog = StandardParametersChoosingDialog::Get(parent);
        if (!pDialog)
        {
            return StandardParametersChoosingDialog::MessageDialogResult::ResultNotSet;
        }
        
        pDialog->m_categoryProperty = categoryProperty;
        pDialog->m_mpExistedParameterDefinitions = existedParameterDefinitions; 
        pDialog->Show();

        pDialog->setModal(true);
        pDialog->exec();

        MessageDialog::MessageDialogResult result = pDialog->GetDialogResult();
        pDialog->GetFinalChoices(finalAdded, finalRemoved);

        pDialog->Resume();

        return result;
    }

    void StandardParametersChoosingDialog::Init()
    {
        // dialog self
        setFixedSize(368, 344);
        setWindowIcon(QIcon());
        setWindowTitle(QString::fromStdWString(GBMP_TR(L"添加标准属性")));
        SetButtons(MessageDialogButton::BtnCancel | MessageDialogButton::BtnOk);
        SetCentralWidgetMargin(QMargins(8, 16, 16, 16));
        
        // central widget
        QWidget *pCentralWidget = NEW_AS_QT(QWidget);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pCentralWidget, L"pCentralWidget为空", L"GMEP", L"2024-01-30");
        pCentralWidget->setObjectName("CentralWidget");
        SetCentralWidget(pCentralWidget);

        // central layout
        QStackedLayout *pCentralLayout = NEW_AS_QT(QStackedLayout);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pCentralLayout, L"pCentralLayout为空", L"GMEP", L"2024-01-30");
        pCentralWidget->setLayout(pCentralLayout);
        pCentralLayout->setContentsMargins(0, 0, 0, 0);
        pCentralLayout->setSpacing(0);
        pCentralLayout->setStackingMode(QStackedLayout::StackingMode::StackAll);

        // mask widget
        m_pLblMask = NEW_AS_QT(QLabel);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pLblMask, L"m_pLblMask为空", L"GMEP", L"2024-01-30");
        pCentralLayout->addWidget(m_pLblMask);
        m_pLblMask->setAlignment(Qt::AlignCenter);
        m_pLblMask->setStyleSheet(
            "QLabel{"
            "font-family:\"Microsoft YaHei\";"
            "font-size:12px;"
            "color:rgba(160, 162, 171, 255);"
            "}"
        );
        m_pLblMask->setVisible(false);

        // content widget
        QWidget *pContentWidget = NEW_AS_QT(QWidget);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pContentWidget, L"pContentWidget为空", L"GMEP", L"2024-01-30");
        pContentWidget->setObjectName("ContentWidget");
        pCentralLayout->addWidget(pContentWidget);
        pCentralLayout->setCurrentWidget(pContentWidget);

        // content layout
        QHBoxLayout *pContentLayout = NEW_AS_QT(QHBoxLayout);
        pContentWidget->setLayout(pContentLayout);
        pContentLayout->setContentsMargins(0, 0, 0, 0);
        pContentLayout->setSpacing(0);
        
        // parameters list
        m_lwParamters = NEW_AS_QT(QListWidget);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_lwParamters, L"m_lwParamters为空", L"GMEP", L"2024-01-30");
        m_lwParamters->setObjectName("ParametersListWidget");
        pContentLayout->addWidget(m_lwParamters);
        m_lwParamters->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        m_lwParamters->setViewMode(QListView::ViewMode::ListMode);
        m_lwParamters->setSpacing(8);
        m_lwParamters->setResizeMode(QListWidget::ResizeMode::Adjust);
        m_lwParamters->setMovement(QListWidget::Movement::Static);
        m_lwParamters->setSelectionMode(QListWidget::SelectionMode::NoSelection);
        m_lwParamters->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
        m_lwParamters->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
        m_lwParamters->setObjectName("ParametersListWidget");
        m_lwParamters->setStyleSheet(
            "QListWidget#ParametersListWidget{"
            "border:none;"
            "background:transparent;"
            "}"
            "QListWidget#ParametersListWidget::Item{"
            "background:rgba(245, 245, 245, 255);"
            "border:none;"
            "}"
        );
        QScrollBar* pScrollBar = m_lwParamters->verticalScrollBar();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pScrollBar, L"pScrollBar为空", L"GMEP", L"2024-01-30");
        pScrollBar->setStyleSheet(
            "QScrollBar:vertical{"
            "width:8px;"
            "background:rgba(0,0,0,0%);"
            "margin:0px,0px,0px,0px;"
            "padding-top:0px;"
            "padding-bottom:0px;"
            "padding-left:1px;"
            "padding-right:1px;"
            "}"
            "QScrollBar::handle:vertical{"
            "width:6px;"
            "background:rgba(35,40,50,20%);"
            "border-radius:2px;"
            "min-height:20;"
            "}"
            "QScrollBar::handle:vertical:hover{"
            "width:6px;"
            "background:rgba(35,40,50,40%);"
            " border-radius:2px;"
            "min-height:20;"
            "}"
            "QScrollBar::add-line:vertical{"
            "height:0px;width:0px;"
            "border-image:url(:/images/icon_triangle_solid_down_8.png);"
            "subcontrol-position:bottom;"
            "}"
            "QScrollBar::sub-line:vertical{"
            "height:0px;width:0px;"
            "border-image:url(:/images/icon_triangle_solid_up_8.png);"
            "subcontrol-position:top;"
            "}"
            "QScrollBar::add-line:vertical:hover{"
            "height:0px;width:0px;"
            "border-image:url(:/images/icon_triangle_solid_down_8.png);"
            "subcontrol-position:bottom;"
            "}"
            "QScrollBar::sub-line:vertical:hover{"
            "height:0px;width:0px;"
            "border-image:url(:/images/icon_triangle_solid_up_8.png);"
            "subcontrol-position:top;"
            "}"
            "QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical{"
            "background:rgba(255,255,255,10%);"
            "border-radius:4px;"
            "}"
        );
        connect(m_lwParamters, &QListWidget::itemClicked, [=](QListWidgetItem *item) {
            if (item)
            {
                QWidget *itemWidget = m_lwParamters->itemWidget(item);
                if (itemWidget)
                {
                    QCheckBox *pCheckBox = static_cast<QCheckBox *>(itemWidget);
                    if (pCheckBox)
                    {
                        pCheckBox->setChecked(!pCheckBox->isChecked());
                    }
                }
            }
        });
        
        // ok button
        m_pBtnOk = MessageDialog::GetButton(MessageDialogButton::BtnOk);
    }

    void StandardParametersChoosingDialog::Resume()
    {
        SetDialogResult(MessageDialogResult::ResultNotSet);

        m_categoryProperty = std::shared_ptr<ICategoryProperty>();
        m_mpExistedParameterDefinitions = std::map<std::wstring, std::shared_ptr<IParameterDefinition>>();
        m_initialSelectedParameterDefinitions = std::map<std::wstring, std::shared_ptr<IParameterDefinition>>();
        m_finalSelectedParameterDefinitions = std::map<std::wstring, std::shared_ptr<IParameterDefinition>>();
        m_errorMessage.clear();
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_lwParamters, L"m_lwParamters为空", L"GMEP", L"2024-01-30");
        m_lwParamters->clear();
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pLblMask, L"m_pLblMask为空", L"GMEP", L"2024-01-30");
        m_pLblMask->clear();
        m_pLblMask->setVisible(false);

        if (m_pBtnOk)
        {
            m_pBtnOk->setFocus();
        }
    }

    void StandardParametersChoosingDialog::Show()
    {
        if (m_categoryProperty)
        {
            for (auto &paramPair : m_categoryProperty->Properties)
            {
                auto parameterDefinition = paramPair.second;
                if (nullptr != parameterDefinition && parameterDefinition->GetIsStandard() && !parameterDefinition->GetIsEssential())
                {
                    auto conflictParamDefIterator = std::find_if(
                        m_mpExistedParameterDefinitions.begin(), 
                        m_mpExistedParameterDefinitions.end(),
                        [parameterDefinition](const std::map<std::wstring, std::shared_ptr<IParameterDefinition>>::value_type &existed) {
                        return
                            existed.second
                            && existed.second->GetName() == parameterDefinition->GetName()
                            && (!existed.second->GetIsStandard())
                            && (existed.second->IsGeometry() || existed.second->GetIsDrivingParameter() || existed.second->GetIsOutputParameter());
                    });

                    if (conflictParamDefIterator != m_mpExistedParameterDefinitions.end())
                    {
                        continue;
                    }
                    
                    QListWidgetItem *item = NEW_AS_QT(QListWidgetItem);
                    //item->setSizeHint(QSize(160, 24));
                    item->setData(Qt::ItemDataRole::UserRole, QString::fromStdWString(parameterDefinition->GetCode()));

                    QCheckBox *pCheckBox = NEW_AS_QT(QCheckBox);
                    QString checkBoxName = QString::fromStdWString(L"CheckBox_%1").arg(QString::fromStdWString(parameterDefinition->GetName()));
                    pCheckBox->setObjectName(checkBoxName);
                    pCheckBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
                    pCheckBox->setText(QString::fromStdWString(parameterDefinition->GetName()));
                    auto foundParamterDefinitionIterator = std::find_if(
                        m_mpExistedParameterDefinitions.begin(),
                        m_mpExistedParameterDefinitions.end(),
                        [parameterDefinition](const std::map<std::wstring, std::shared_ptr<IParameterDefinition>>::value_type &pair) {                      
                        return (pair.second && pair.second->GetCode() == parameterDefinition->GetCode());
                    });
                    if (foundParamterDefinitionIterator != m_mpExistedParameterDefinitions.end())
                    {
                        m_initialSelectedParameterDefinitions[parameterDefinition->GetName()] = parameterDefinition;
                        pCheckBox->setCheckState(Qt::CheckState::Checked);
                    }
                    DBG_WARN_AND_CONTINUE_UNLESS(m_lwParamters, L"m_lwParamters为空", L"GMEP", L"2024-01-30");
                    m_lwParamters->addItem(item);
                    m_lwParamters->setItemWidget(item, pCheckBox);
                }
            }
        }
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_lwParamters, L"m_lwParamters为空", L"GMEP", L"2024-01-30");
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pLblMask, L"m_pLblMask为空", L"GMEP", L"2024-01-30");
        if (m_lwParamters->count() > 0)
        {
            m_pLblMask->setVisible(false);
            m_pLblMask->clear();
        }
        else
        {
            m_pLblMask->setText(QString::fromStdWString(GBMP_TR(L"没有可供选择的参数")));
            m_pLblMask->setVisible(true);
        }
    }

    void StandardParametersChoosingDialog::GetFinalChoices(std::map<std::wstring, std::shared_ptr<IParameterDefinition>> &added, std::map<std::wstring, std::shared_ptr<IParameterDefinition>> &removed)
    {
        m_finalSelectedParameterDefinitions.clear();
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_lwParamters, L"m_lwParamters为空", L"GMEP", L"2024-01-30");
        for (int i = 0; i != m_lwParamters->count(); ++i)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_categoryProperty, L"m_categoryProperty为空", L"GMEP", L"2024-01-30")
            auto item = m_lwParamters->item(i);
            if (item)
            {
                QWidget *itemWidget = m_lwParamters->itemWidget(item);
                if (itemWidget)
                {
                    QCheckBox *pCheckBox = static_cast<QCheckBox *>(itemWidget);
                    if (pCheckBox && pCheckBox->isChecked())
                    {
                        auto code = item->data(Qt::ItemDataRole::UserRole).toString().toStdWString();

                        auto foundParamDefIterator = std::find_if(
                            m_categoryProperty->Properties.begin(),
                            m_categoryProperty->Properties.end(),
                            [code](const std::map<std::wstring, std::shared_ptr<IParameterDefinition>>::value_type &prop) {
                            return (prop.second != nullptr) && (prop.second->GetCode() == code);
                        });

                        if (foundParamDefIterator != m_categoryProperty->Properties.end() && foundParamDefIterator->second)
                        {
                            m_finalSelectedParameterDefinitions[foundParamDefIterator->second->GetName()] = foundParamDefIterator->second;
                        }
                    }
                }
            }
        }

        for (auto &intialSelectedParamDefPair : m_initialSelectedParameterDefinitions)
        {
            auto initalSelectedParamDef = intialSelectedParamDefPair.second;
            if (initalSelectedParamDef)
            {
                auto matched = m_finalSelectedParameterDefinitions.find(initalSelectedParamDef->GetName());
                if (matched == m_finalSelectedParameterDefinitions.end())
                {
                    removed[initalSelectedParamDef->GetName()] = initalSelectedParamDef;
                }
            }
        }

        for (auto &finalSelectedParamDefPair : m_finalSelectedParameterDefinitions)
        {
            auto finalSelectedParamDef = finalSelectedParamDefPair.second;
            if (finalSelectedParamDef)
            {
                auto matched = m_initialSelectedParameterDefinitions.find(finalSelectedParamDef->GetName());
                if (matched == m_initialSelectedParameterDefinitions.end())
                {
                    added[finalSelectedParamDef->GetName()] = finalSelectedParamDef;
                }
            }
        }
    }
}